#!/bin/sh

if [ $# -lt 1 ]; then
    echo Usage: class.sh classname
    exit 1
fi

classname=$1
here=`pwd`
target="$here"
while [ ! -f "$target/PROJECT_INFO" -a "$target" != "/" ];
do
    target=`dirname "$target"`
done
cd "$here"

if [ -f "$target/PROJECT_INFO" ]; then
    . "$target/PROJECT_INFO"
else
    echo "PROJECT_INFO not found!"
    exit 1
fi

if [ "$product" = "" ]; then
    echo "product not defined!"
    exit 1
fi

if [ "startyear" = "" ]; then
    echo "startyear not defined!"
    exit 1
fi

namespace=$(pwd | sed -e "s:$target::" -e "s,/, ,g" -e "s/^ //")

now="-`date +%Y`"
if [ "$now" = "-$startyear" ]; then
    now=""
fi

mcn=$(echo $classname | \
    sed -e 's/[A-Z]/_&/g' \
        -e 's/./\U&/g' \
        -e 's/^_//')
mfn=$(echo $classname | sed -e 's/./\l&/g')

mnn=""
revnamespace="engine"
for item in $namespace
do
    mnn=${mnn}_${item}
    revnamespace="$item $revnamespace"
done
mnn=$(echo $mnn | sed -e 's/./\U&/g' | sed -e 's/^_//')

nbb=`cat << EOF
namespace engine
{

EOF
for item in $namespace
do
    cat <<EOF
namespace $item
{

EOF
done`

nbe=`for item in $revnamespace
do
    cat <<EOF
} // namespace $item

EOF
done`

nip="../src/"
for item in $namespace
do
    nip="$nip$item/"
done

##############################################################################
# Header
##############################################################################
cat <<EOF > src/$mfn.h
//
// $product
//
// Copyright $startyear$now CG & CAD Institute, Tsinghua University.
// All rights reserved.
//

#ifndef __ENGINE_${mnn}_${mcn}_APPEARED__
#define __ENGINE_${mnn}_${mcn}_APPEARED__

$nbb

/**
 * TODO:
 */
class $classname
{
// public type forward-declarations & typedefs & defs
public:

// public constructors & destructor
public:
    /**
     * TODO:
     */
    $classname(void);
    virtual ~$classname(void);

// public member functions
public:

// public static member functions
public:

// protected type forward-declarations & typedefs & defs
protected:

// protected member functions
protected:

// protected static member functions
protected:

// private type forward-declarations & typedefs & defs
private:

// private member functions
private:

// private static member functions
private:

// private data members
private:

// protected constructors & destructor
protected:

// private constructors & destructor
private:
    // Disable the evil constructor and assignment operator.
    $classname(const $classname&);
    $classname& operator=(const $classname&);
};

$nbe

#endif // __ENGINE_${mnn}_${mcn}_APPEARED__
EOF

##############################################################################
# Source
##############################################################################
cat <<EOF > src/$mfn.cpp
//
// $product
//
// Copyright $startyear$now CG & CAD Institute, Tsinghua University.
// All rights reserved.
//

#include "$mfn.h"

// C++ headers
//#include <iostream>

// C headers
//#include <stdio.h>

// User headers
//#include "my_header.h"

$nbb

$classname::$classname(void)
{
    // TODO:
}

$classname::~$classname(void)
{
    // TODO:
}

$nbe
EOF

mkdir -p test

##############################################################################
# Test suite
##############################################################################
cat <<EOF > test/${mfn}test.cpp
//
// $product
//
// Copyright $startyear$now CG & CAD Institute, Tsinghua University.
// All rights reserved.
//

#include "$nip$mfn.h"

// CppUnit headers
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/CompilerOutputter.h>

// C++ headers
#include <string>

// C headers
//#include <stdio.h>

// User headers
//#include "my_header.h"

$nbb

namespace test
{

class ${classname}Test : public CppUnit::TestFixture
{
    CPPUNIT_TEST_SUITE(${classname}Test);

    // Test cases
    //CPPUNIT_TEST(testSample);

    CPPUNIT_TEST_SUITE_END();

// public type forward-declarations & typedefs & defs
public:

// public constructors & destructor
public:
    ${classname}Test(void);
    virtual ~${classname}Test(void);

// setUp & tearDown
public:
    virtual void setUp(void);
    virtual void tearDown(void);

// test cases
private:
    //void testSample(void);

// public member functions
public:

// public static member functions
public:

// protected type forward-declarations & typedefs & defs
protected:

// protected member functions
protected:

// protected static member functions
protected:

// private type forward-declarations & typedefs & defs
private:

// private member functions
private:

// private static member functions
private:

// private data members
private:

// protected constructors & destructor
protected:

// private constructors & destructor
private:
    // Disable the evil constructor and assignment operator.
    ${classname}Test(const ${classname}Test&);
    ${classname}Test& operator=(const ${classname}Test&);
};

CPPUNIT_TEST_SUITE_REGISTRATION(${classname}Test);

${classname}Test::${classname}Test(void)
{
}

${classname}Test::~${classname}Test(void)
{
}

void ${classname}Test::setUp(void)
{
}

void ${classname}Test::tearDown(void)
{
}

//void ${classname}Test::testSample(void)
//{
//    CPPUNIT_ASSERT(condition);
//    CPPUNIT_FAIL(message);
//    CPPUNIT_ASSERT_EQUAL(expected, actual);
//    CPPUNIT_ASSERT_EQUAL_MESSAGE(message, expected, actual);
//    CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta);
//    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(message, expected, actual, delta);
//}

} // namespace test

$nbe

int main(int argc, char* argv[])
{
    CppUnit::TextUi::TestRunner runner;
    std::string format = CPPUNIT_COMPILER_LOCATION_FORMAT;
    size_t state = 0;
    for (std::string::size_type i = 0; i < format.size(); ++i)
    {
        if (state == 0 &&format[i] == '%')
        {
            state = 1;
        }
        else
        {
            if (format[i] == 'f')
                format[i] = 'p';
            state = 0;
        }
    }
    CppUnit::CompilerOutputter* outputter =
        new CppUnit::CompilerOutputter(&runner.result(),
                                       std::cout,
                                       format.c_str());
    runner.setOutputter(outputter);
    CppUnit::TestSuite* suite = new CppUnit::TestSuite();
    CppUnit::TestFactoryRegistry& registry =
        CppUnit::TestFactoryRegistry::getRegistry();
    runner.addTest(registry.makeTest());
    runner.addTest(suite);
    return runner.run("", false) ? 0 : 1;
}
EOF
